#include "StdAfx.h"
#include "LaserMesh.h"
#include "GraphicsController.h"
#include <stdexcept>
#include <string>


///////////////////////////////////////////////////////////////////////////////

DWORD CLaserVertex::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

///////////////////////////////////////////////////////////////////////////////

LaserMesh::LaserMesh(CGraphicsController& graphicsController)
      : m_d3Device(graphicsController.getD3Device()),
      m_vertexBuffer(NULL),
      m_indexBuffer(NULL)
{
   m_vertexBuffer = graphicsController.createVertexBuffer(16 * sizeof(CLaserVertex),
                                                          D3DUSAGE_WRITEONLY,
                                                          CLaserVertex::FVF,
                                                          D3DPOOL_MANAGED);

   m_indexBuffer = graphicsController.createIndexBuffer(16 * sizeof(WORD),
                                                        D3DUSAGE_WRITEONLY,
                                                        D3DFMT_INDEX16,
                                                        D3DPOOL_MANAGED);

   CLaserVertex* pVertex = NULL;
   HRESULT res = m_vertexBuffer->Lock(0, 0, (void**)&pVertex, D3DLOCK_DISCARD);
   if (FAILED(res))
   {
      throw std::logic_error(
         std::string("Unable to lock a vertex buffer"));
   }

   DWORD grey = 0xFFCCCCCC;
   *pVertex++ = CLaserVertex( -0.1f, -0.1f,   0, grey );
   *pVertex++ = CLaserVertex( -0.1f, -0.1f, 100, grey );
   *pVertex++ = CLaserVertex(  0.1f, -0.1f, 100, grey );
   *pVertex++ = CLaserVertex(  0.1f, -0.1f,   0, grey );
   *pVertex++ = CLaserVertex( -0.1f,  0.1f,   0, grey );
   *pVertex++ = CLaserVertex( -0.1f,  0.1f, 100, grey );
   *pVertex++ = CLaserVertex(  0.1f,  0.1f, 100, grey );
   *pVertex++ = CLaserVertex(  0.1f,  0.1f,   0, grey );

   DWORD white = 0xFFFFFFFF;
   *pVertex++ = CLaserVertex( -0.3f, -0.3f,   0, white );
   *pVertex++ = CLaserVertex( -0.3f, -0.3f, 100, white );
   *pVertex++ = CLaserVertex(  0.3f, -0.3f, 100, white );
   *pVertex++ = CLaserVertex(  0.3f, -0.3f,   0, white );
   *pVertex++ = CLaserVertex( -0.3f,  0.3f,   0, white );
   *pVertex++ = CLaserVertex( -0.3f,  0.3f, 100, white );
   *pVertex++ = CLaserVertex(  0.3f,  0.3f, 100, white );
   *pVertex++ = CLaserVertex(  0.3f,  0.3f,   0, white );

   m_vertexBuffer->Unlock();

   WORD* pIndex = NULL;
   res = m_indexBuffer->Lock(0, 0, (void**)&pIndex, D3DLOCK_DISCARD);
   if (FAILED(res))
   {
      throw std::logic_error(
         std::string("Unable to lock an index buffer"));
   }

   *pIndex++ = 5;
   *pIndex++ = 6;
   *pIndex++ = 4;
   *pIndex++ = 7;
   *pIndex++ = 0;
   *pIndex++ = 3;
   *pIndex++ = 1;
   *pIndex++ = 2;
   *pIndex++ = 3;
   *pIndex++ = 7;
   *pIndex++ = 2;
   *pIndex++ = 6;
   *pIndex++ = 1;
   *pIndex++ = 5;
   *pIndex++ = 0;
   *pIndex++ = 4;

   m_indexBuffer->Unlock();

   m_boundingBox.min.x = -0.3f; m_boundingBox.min.y = -0.3f; m_boundingBox.min.z =   0;
   m_boundingBox.max.x =  0.3f; m_boundingBox.max.y =  0.3f; m_boundingBox.max.z = 100;
}

///////////////////////////////////////////////////////////////////////////////

LaserMesh::~LaserMesh(void)
{
   if (m_vertexBuffer != NULL)
   {
      m_vertexBuffer->Release();
      m_vertexBuffer = NULL;
   }

   if (m_indexBuffer != NULL)
   {
      m_indexBuffer->Release();
      m_indexBuffer = NULL;
   }
}

///////////////////////////////////////////////////////////////////////////////

void LaserMesh::render()
{
   m_d3Device.SetStreamSource(0, m_vertexBuffer, 0, sizeof(CLaserVertex));
   m_d3Device.SetIndices(m_indexBuffer); 
   m_d3Device.SetFVF(CLaserVertex::FVF);

   // we don't want the lights affecting the laser
   m_d3Device.SetRenderState(D3DRS_LIGHTING, FALSE);
   m_d3Device.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
   m_d3Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
   m_d3Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
   
   // first pass - draw the laser's core
   m_d3Device.DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, 8, 0, 14);

   // second pass - draw the laser's glow
   m_d3Device.DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 8, 0, 8, 0, 14);

   // cleanup
   m_d3Device.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
   m_d3Device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
   m_d3Device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
   m_d3Device.SetRenderState(D3DRS_LIGHTING, TRUE);
}

///////////////////////////////////////////////////////////////////////////////
